/*
 * 版权信息: © 聚均科技
 */
package cn.xiaoke.util;


import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author xiaokedamowang
 * @version 1.0
 * @date 2022/1/6 15:53
 */
@Slf4j
public class XkExcelUtils {

    @Data
    @Accessors(chain = true)
    static class ExcelInfo<T, R> {
        /**
         * 中文名字
         */
        private String name;

        /**
         * 哪个属性
         */
        private Field field;

        /**
         * 对应的get方法
         */
        private Method getMethod;
        /**
         * 排序
         */
        private int ord;
        /**
         * 转换处理类
         */
        private Class<? extends Excel.ExcelConvert<T, R>> convertClazz;
        /**
         * 转换处理类实例
         */
        private Excel.ExcelConvert<T, R> convert;


        public String getContent(T obj) {
            if (obj == null) {
                return null;
            }
            return Optional.ofNullable(convert).map(cv -> cv.output(obj)).orElse(obj.toString());
        }

    }

    /**
     * 分析注解 获取表头信息
     *
     * @param clazz 类
     * @return java.util.List<com.fusionfintrade.servicecore.support.XkExcelUtils.ExcelInfo>
     * @author xiaokedamowang
     * @date 2022-01-07 09:51
     */
    @SuppressWarnings("unchecked")
    private static <T, R> List<ExcelInfo<T, R>> createInfo(Class<?> clazz, String group) {
        return Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(Excel.class) || field.isAnnotationPresent(Excel.List.class))
                .map(field -> {
                    ExcelInfo<T, R> excelInfo = null;
                    try {
                        final String fieldName = field.getName();
                        Excel an;
                        if (field.isAnnotationPresent(Excel.List.class)) {
                            an = Arrays.stream(field.getAnnotation(Excel.List.class).value())
                                    .filter(anno -> Objects.equals(group, anno.group()))
                                    .findFirst().orElseThrow(() -> new RuntimeException("没有找到分组"));
                        } else {
                            an = Stream.of(field.getAnnotation(Excel.class))
                                    .filter(anno -> Objects.equals(Excel.DEFAULT_GROUP, group) || Objects.equals(group, anno.group()))
                                    .findFirst().orElseThrow(() -> new RuntimeException("没有找到分组"));
                        }

                        String name = fieldName;
                        name = Optional.ofNullable(field.getAnnotation(ApiModelProperty.class)).map(ApiModelProperty::value).filter(StringUtils::isNotBlank).orElse(name);
                        name = Optional.ofNullable(an.value()).filter(StringUtils::isNotBlank).orElse(name);

                        field.setAccessible(true);
                        excelInfo = new ExcelInfo<T, R>().setName(name).setOrd(an.ord()).setField(field);
                        StringBuilder sb = new StringBuilder(fieldName);
                        sb.replace(0, 1, String.valueOf(sb.charAt(0)).toUpperCase()).insert(0, "get");

                        excelInfo.setGetMethod(clazz.getDeclaredMethod(sb.toString()));

                        ExcelInfo<T, R> finalExcelInfo = excelInfo;
                        Optional.ofNullable(an.convert()).ifPresent((conv) -> {
                            try {
                                finalExcelInfo.setConvertClazz((Class<? extends Excel.ExcelConvert<T, R>>) conv).setConvert(conv.newInstance());
                            } catch (Exception e) {
                                log.info("XkExcelUtils.createHead.newInstance出错:", e);
                            }
                        });
                    } catch (Exception ignored) {
                    }
                    return excelInfo;
                }).filter(Objects::nonNull).sorted(Comparator.comparingInt(ExcelInfo::getOrd)).collect(Collectors.toList());
    }

//    /**
//     * 传入参数 生成workbook
//     *
//     * @param name     标题和sheet名字
//     * @param userName 用户名
//     * @param source   数据源
//     * @param clazz    类
//     * @return org.apache.poi.ss.usermodel.Workbook
//     * @author xiaokedamowang
//     * @date 2022-01-07 09:50
//     */
//    public static <T> Workbook goToWorkbook(String name, String userName, List<T> source, Class<?> clazz) throws IOException {
//        return goToWorkbook(name, userName, source, clazz, Excel.DEFAULT_GROUP);
//    }
//
//    /**
//     * 传入参数 生成workbook
//     *
//     * @param name     标题和sheet名字
//     * @param userName 用户名
//     * @param source   数据源
//     * @param clazz    类
//     * @param group    分组
//     * @return org.apache.poi.ss.usermodel.Workbook
//     * @author xiaokedamowang
//     * @date 2022-01-07 09:50
//     */
//    public static <T, R> Workbook goToWorkbook(String name, String userName, List<T> source, Class<?> clazz, String group) throws IOException {
//        final List<ExcelInfo<T, R>> infos = createInfo(clazz, group);
//        final String[] heads = infos.stream().map(ExcelInfo::getName).toArray(String[]::new);
//        final List<String[]> dataList = createDataList(source, infos);
//        Map<String, List<Map<String, Object>>> styleMap = ExcelUtils.createDefaultTableStyle(heads.length);
//        return ExcelUtils.writeToWorkbook(name, heads, dataList, styleMap, userName, name);
//    }
//
//    /**
//     * 创建需要的数据
//     *
//     * @param datas 数据源
//     * @param infos 数据的元信息
//     * @return java.util.List<java.lang.String [ ]>
//     * @author xiaokedamowang
//     * @date 2022-01-07 09:50
//     */
//    @SuppressWarnings("unchecked")
//    private static <T, R> List<String[]> createDataList(List<T> datas, List<ExcelInfo<T, R>> infos) {
//        return datas.stream().map(
//                d -> infos.stream().map(info -> Optional.ofNullable(info.getMethod).map(method -> {
//                    try {
//                        return info.getContent((T) ConvertUtils.convert(method.invoke(d), method.getReturnType()));
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                    return null;
//                }).orElseGet(() -> {
//                    try {
//                        final Field field = info.getField();
//                        return info.getContent((T) ConvertUtils.convert(field.get(d), field.getType()));
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                    return null;
//                })).toArray(String[]::new)
//        ).collect(Collectors.toList());
//    }

//    /**
//     * 传入参数 生成base64的excel文件 放进map返回
//     *
//     * @param fileNamePre 文件名前缀
//     * @param name        标题和sheet名字
//     * @param userName    用户名
//     * @param source      数据源
//     * @param clazz       类
//     * @param group       分组
//     * @return java.util.Map<java.lang.String, java.lang.Object>
//     * @author xiaokedamowang
//     * @date 2022-01-07 09:47
//     */
//    public static <T> Map<String, Object> goToWorkbookBase64(String fileNamePre, String name, String userName
//            , List<T> source, Class<?> clazz, String group) throws IOException {
//        final Workbook workbook = goToWorkbook(name, userName, source, clazz, group);
//        ByteArrayOutputStream bos = new ByteArrayOutputStream();
//        workbook.write(bos);
//        byte[] wbByte = bos.toByteArray();
//        Map<String, Object> respMap = new HashMap<>(2);
//        respMap.put("fileContent", "data:application/x-xls;base64," + new Base64().encodeToString(wbByte));
//        respMap.put("fileName", fileNamePre + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx");
//        return respMap;
//    }

//    /**
//     * 传入参数 生成base64的excel文件 放进map返回
//     *
//     * @param fileNamePre 文件名前缀
//     * @param name        标题和sheet名字
//     * @param userName    用户名
//     * @param source      数据源
//     * @param clazz       类
//     * @return java.util.Map<java.lang.String, java.lang.Object>
//     * @author xiaokedamowang
//     * @date 2022-01-07 09:47
//     */
//    public static <T> Map<String, Object> goToWorkbookBase64(String fileNamePre, String name, String userName
//            , List<T> source, Class<?> clazz) throws IOException {
//        return goToWorkbookBase64(fileNamePre, name, userName, source, clazz, Excel.DEFAULT_GROUP);
//    }

}
